<script setup lang="ts">
import { tableConfig } from './config/table-config';
import { formConfig } from './config/form-config';
import equipment from '@/views/Modeling/ProcessManagement/view/ProcedureList/dialog/equipment/index.vue';
import auxiliary from '@/views/Modeling/ProcessManagement/view/ProcedureList/dialog/auxiliary/index.vue';
import { formatInput, generateId, transformValue, isArray, hideValidErrText } from '@/utils';
import { generateNameToLevel } from '@/config/constant';
import { doGetProcedureDetail, doUpdateProcedureList } from '@/api/procedure/index';
import { cloneDeep, isEqual } from 'lodash-es';
import { Message, Modal } from '@/instance';
import type { EquipmentData } from '@/api/modeling/equipment/model/type';
import type { AuxiliaryData } from '@/api/modeling/auxiliaryResources/model/type';
import type {
    ProcedureData,
    WorkingProcedureEquipments,
    WorkingProcedureAuxiliary
} from '@/api/procedure/model/type';

const initProcedureForm = () => ({
    processCode: null,
    processName: null,
    remarks: null
});

interface InitProcedureForm {
    [key: string]: any;
    processCode: string | null;
    processName: string | null;
    remarks: string | null;
}
const procedureForm = ref<InitProcedureForm>(initProcedureForm());

const excludeKey = ref([]);
const {
    handleFullscreen,
    visible,
    getMaxHeight,
    handleCancel,
    loading,
    modalSlotRef: tableRef
} = useModal({
    appendData: procedureForm,
    excludeKey
});

const emit = defineEmits(['updateSuccess']);
/**
 * 校验相关
 */
const {
    popoverVisible,
    popoverErrMsg,
    handleInput,
    handleFocus,
    resetRelatedValid,
    handleValidFieldPass
} = useValid({
    position: 'left',
    formConfig: formConfig.items,
    formFields: procedureForm
});

/**
 * @: 打开弹框
 */
let cacheEquipmentsData: WorkingProcedureEquipments;
let id: string;
const open = async (procedureId?: string) => {
    try {
        if (procedureId == null) throw new Error('工序id 不存在');
        visible.value = true;
        id = procedureId;
        const { data } = await doGetProcedureDetail(id);
        if (data) {
            const {
                processCode,
                processName,
                remarks,
                workingProcedureEquipments: equipmentsData
            } = data;

            // 更新表单工序编码、工序名称、工序描述信息
            procedureForm.value = {
                processCode,
                processName,
                remarks
            };

            // 处理返回的加工设备数据
            equipmentsData.map((equipment: WorkingProcedureEquipments) => {
                equipment.markId = generateId(); // 生成设备标记 id时，用于新增设备编码时，区分同一工序下不同设备编码
                if (equipment.workingProcedureAuxiliary.length) {
                    // 存在辅助资源编码信息
                    equipment.workingProcedureAuxiliary.map(
                        (auxiliary: WorkingProcedureAuxiliary) => {
                            auxiliary.markId = generateId(); // 生成辅助资源标记 id，用于新增辅助资源编码时，区分同一工序同一设备下不同辅助资源编码
                            auxiliary.pMarkId = equipment.markId; // 生成辅助资源父标记 id，用于标注当前辅助资源对应哪一个设备
                        }
                    );
                } else {
                    const auxiliaryData = cloneDeep(initAuxiliary);
                    auxiliaryData.markId = generateId();
                    auxiliaryData.pMarkId = equipment.markId;
                    equipment.workingProcedureAuxiliary = [auxiliaryData];
                }
            });

            tableRef.value.tableData = equipmentsData;
            cacheEquipmentsData = cloneDeep(equipmentsData); // 缓存初始数据，用于提交时对比数据是否发生改变。
        }
    } catch (error: any) {
        Message.error(error.message);
    }
};

/**
 * 更新工序
 */
const updateProcedureList = async () => {
    const tableData = cloneDeep(tableRef.value.tableData);
    // 处理提交表格数据，删除不必要字段，保留后端接口需要的相关字段
    const workingProcedureEquipments = tableData.map(
        (equipmentItem: WorkingProcedureEquipments) => {
            delete equipmentItem.markId;

            equipmentItem.workingProcedureAuxiliary =
                equipmentItem.workingProcedureAuxiliary.filter(auxiliaryItem => {
                    delete auxiliaryItem.pMarkId;
                    delete auxiliaryItem.markId;

                    return auxiliaryItem.auxiliaryId;
                });
            return equipmentItem;
        }
    );
    const data = {
        id,
        ...procedureForm.value,
        workingProcedureEquipments
    };

    try {
        loading.value = true;
        const res = await doUpdateProcedureList(data);
        if (res) {
            visible.value = false;
            loading.value = false;
            Message.success(`操作成功！`);
            emit('updateSuccess');
        }
        return res;
    } finally {
        loading.value = false;
    }
};

/**
 * @: 点击确定按钮
 */
const submit = async () => {
    const formValid = handleValidFieldPass();
    const tableValid = tableRef.value?.handleValidFieldPass();

    if (formValid && tableValid) {
        try {
            const isTableValueChange = isEqual(cacheEquipmentsData, tableRef.value.tableData); // 对比设备编码表格数据与初始化时后端给与的表格数据是否相等，不相等说明设备编码或辅助资源数据有发生改变
            if (!isTableValueChange) {
                Modal.confirm({
                    title: '确认要修改工序吗？',
                    content:
                        '当前工序已创建工艺路线，若工序变更了设备或辅助资源，则本次修改仅对新建的工艺路线生效，历史工艺路线重新编辑后可生效！',
                    onOk: () => {
                        updateProcedureList();
                    }
                });
                return;
            }
            updateProcedureList();
        } catch (error) {
            console.log('error', error);
        }
    }
};

/**
 * @: 初始化数据
 * @return {*}
 */
const initData = () => {
    procedureForm.value = initProcedureForm();
};

/**
 * @: 设备编码相关逻辑
 */
const equipmentRef = ref<InstanceType<typeof equipment>>();
let currentMarkId: string | null = null; // 记录当前选择设备的标记id, 用于选择设备后匹配对应工序下所处设备，并回显使用
let validIndex = 0;
const openEquipment = (row: WorkingProcedureEquipments, index: number) => {
    validIndex = index;
    currentMarkId = row.markId as string;
    equipmentRef.value?.open(row.equipmentId!);
};

/**
 * @: 设备编码弹框点击确定
 */
const equipmentSubmit = (row: EquipmentData) => {
    if (isArray(row)) return;
    resetRelatedValid(['1'], validIndex); // 移除当前校验
    const workingProcedureEquipment = tableRef.value.tableData.filter(
        (item: WorkingProcedureEquipments) => item.markId === currentMarkId
    )[0];

    if (workingProcedureEquipment) {
        workingProcedureEquipment.equipmentId = row.id!; // 设备id
        workingProcedureEquipment.equipmentNumber = row.equipmentNumber; // 设备编码
        workingProcedureEquipment.deviceName = row.deviceName; // 设备名称
    }
};

/**
 * @: 辅助资源相关逻辑
 */
const auxiliaryRef = ref<InstanceType<typeof auxiliary>>();
let currentPMarkId: string | null = null;
const openAuxiliary = (row: WorkingProcedureAuxiliary) => {
    currentPMarkId = row.pMarkId as string; // 记录当前辅助资源父标记markId, 用于选择辅助资源后，匹配对应当前工序中所处哪一个设备中。
    currentMarkId = row.markId as string; // 记录当前辅助资源标记markId, 用于选择辅助资源后，匹配当前工序所处设备中哪一个辅助资源，并匹配对应辅助资源进行数据更新操作。
    auxiliaryRef.value?.open(row.auxiliaryId!);
};

/**
 * @: 辅助资源弹框点击确定
 */
const auxiliarySubmit = (row: AuxiliaryData) => {
    if (isArray(row)) return;
    // 根据记录父标记markId, 匹配得到对应设备数据
    const workingProcedureEquipment = tableRef.value.tableData.filter(
        (item: WorkingProcedureEquipments) => item.markId === currentPMarkId
    )[0];

    if (workingProcedureEquipment) {
        // 根据记录标记markId, 匹配得到当前对应设备的辅助资源
        const workingProcedureAuxiliary =
            workingProcedureEquipment.workingProcedureAuxiliary.filter(
                (item: WorkingProcedureAuxiliary) => item.markId === currentMarkId
            )[0];
        if (workingProcedureAuxiliary) {
            workingProcedureAuxiliary.auxiliaryId = row.id; // 辅助资源id
            workingProcedureAuxiliary.auxiliaryDataCoding = row.auxiliaryResourceCoding; // 辅助资源编码
            workingProcedureAuxiliary.auxiliaryResourceName = row.auxiliaryResourceName; // 辅助资源名称
        }
    }
};

// 监听表格数据变化，初始化设备编码与辅助资源选项
const initAuxiliary: WorkingProcedureAuxiliary = {
    auxiliaryId: null,
    auxiliaryResourceName: null,
    auxiliaryDataCoding: null
};
const initEquipmentData: WorkingProcedureEquipments = {
    equipmentId: null,
    equipmentNumber: null,
    deviceName: null,
    workingProcedureAuxiliary: [initAuxiliary]
};

const handleAdd = (data: ProcedureData[]) => {
    if (data == null) return;
    const markId = generateId(); // 生成标记 id
    const equipmentData = cloneDeep(initEquipmentData);
    data.map((item: ProcedureData) => {
        if (!item.workingProcedureEquipments) {
            equipmentData.markId = markId;
            equipmentData.workingProcedureAuxiliary.map(item => {
                item.markId = item.pMarkId = markId;
            });
            item.workingProcedureEquipments = [equipmentData];
        }
    });
};

/**
 * 重新初始化生成设备编码数据
 */
const regenEquipMent = () => {
    const markId = generateId(); // 生成标记 id
    const equipmentData = cloneDeep(initEquipmentData);
    equipmentData.markId = markId;
    equipmentData.workingProcedureAuxiliary.map(item => {
        item.markId = item.pMarkId = markId;
    });
    return equipmentData;
};

/**
 * 当前工序下新增对应设备编码
 */
const addEquipment = (id: string) => {
    const workingProcedureEquipments = tableRef.value.tableData;
    const rowIndex = workingProcedureEquipments.findIndex(
        (item: WorkingProcedureEquipments) => item.markId === id
    );
    const equipmentData = regenEquipMent();
    workingProcedureEquipments.splice(rowIndex + 1, 0, equipmentData);
};

/**
 * 删除当前工序下的对应设备
 */
const delEquipment = (id: string, index: number) => {
    const workingProcedureEquipments = tableRef.value.tableData;
    if (workingProcedureEquipments.length === 1) {
        tableRef.value.tableData = [regenEquipMent()]; // 当前工序下只有一个设备时进行数据重置初始化。
    } else {
        const rowIndex = workingProcedureEquipments.findIndex(
            (item: WorkingProcedureAuxiliary) => item.markId === id
        );
        workingProcedureEquipments.splice(rowIndex, 1);
    }
    resetRelatedValid(['1'], index); // 清除校验失败样式
    // 实时监听表单校验文案提示
    hideValidErrText(() => {
        tableRef.value.errValidRef = null; // 隐藏表格校验提示文案
    }, tableRef.value.$el);
};

/**
 * 清空工序所选的当前设备
 */
const clearEquipmentSelect = (row: WorkingProcedureEquipments) => {
    row.deviceName = null;
    row.equipmentId = null;
};

/**
 * 重新初始化生成辅助资源编码
 */
const regenAuiliary = (pMarkId: string) => {
    const markId = generateId();
    const auiliaryData = cloneDeep(initAuxiliary);
    auiliaryData.pMarkId = pMarkId;
    auiliaryData.markId = markId;
    return auiliaryData;
};

/**
 * 新增当前工序所在设备下的辅助资源编码
 */
const addAuxiliary = (auxilary: WorkingProcedureAuxiliary) => {
    const auxiliaryData = tableRef.value.tableData.filter(
        (item: WorkingProcedureEquipments) => item.markId === auxilary.pMarkId
    )[0];
    const data = regenAuiliary(auxilary.pMarkId as string);

    const rowIndex = auxiliaryData.workingProcedureAuxiliary.findIndex(
        (item: WorkingProcedureAuxiliary) => item.markId === auxilary.markId
    );
    auxiliaryData.workingProcedureAuxiliary.splice(rowIndex + 1, 0, data);
};

/**
 * 删除当前工序所在设备下的辅助资源编码
 */
const delAuxiliary = (auxilary: WorkingProcedureAuxiliary) => {
    const auxiliaryData = tableRef.value.tableData.filter(
        (item: WorkingProcedureEquipments) => item.markId === auxilary.pMarkId
    )[0];
    const { workingProcedureAuxiliary } = auxiliaryData;

    if (workingProcedureAuxiliary.length === 1) {
        auxiliaryData.workingProcedureAuxiliary = [regenAuiliary(auxilary.pMarkId as string)]; // 当前工序中所处的设备下只存在一个辅助资源时进行数据重置初始化。
    } else {
        const rowIndex = workingProcedureAuxiliary.findIndex(
            (item: WorkingProcedureAuxiliary) => item.markId === auxilary.markId
        );
        workingProcedureAuxiliary.splice(rowIndex, 1);
    }
};

/**
 * 清空工序所选设备中下对应的当前辅助编码
 */
const clearAuxiliarySelect = (row: WorkingProcedureAuxiliary) => {
    row.auxiliaryResourceName = null;
    row.auxiliaryId = null;
};

/**
 * 新增当前工序所属设备的辅助资源时，动获取动态设备编码&设备名称内边距
 * @tip {50.67} 表示一个单元格高度
 * @tip {8} 表示默认单元格下内边距的值
 */
const getDynamicPBottom = (auxilary: WorkingProcedureAuxiliary[]) => {
    const len = auxilary.length - 1;
    const bNum = 8;
    const pBottom = !len ? bNum : bNum + 50.67 * len;

    return pBottom + 'px';
};

defineExpose({
    open
});
</script>

<template>
    <div>
        <q-modal
            v-model:visible="visible"
            title="编辑"
            :fullscreen="true"
            width="960px"
            :close-cancel="true"
            :centered="true"
            :after-close="initData"
            :confirm-loading="loading"
            @fullscreen="handleFullscreen"
            @ok="submit"
            @cancel="handleCancel"
        >
            <div :id="generateNameToLevel('3')" class="p-l-8 p-r-8">
                <el-row :gutter="32" class="p-l-8 p-r-8">
                    <el-col
                        v-for="item in formConfig.items"
                        :key="item.validProps?.id"
                        :span="12"
                        class="role-main__header form-common m-b-18"
                    >
                        <label class="is-column"
                            ><span>{{ item.validProps?.required ? '*' : '&nbsp;' }}</span
                            >{{ item.columnProps?.label }}:</label
                        >
                        <q-form-item :id="item.validProps?.id!" class="role-main-form__item">
                            <el-input
                                v-model.trim="procedureForm[item.modelKey!]"
                                v-bind="item.elInputProps"
                                :placeholder="`请输入${item.columnProps?.label}`"
                                @focus="
                                    (e: any) =>
                                        handleFocus(e, procedureForm, {
                                            config: item
                                        })
                                "
                                @input="
                                    procedureForm[item.modelKey!] = formatInput(
                                        procedureForm,
                                        item.modelKey!,
                                        item.validFormatType
                                    )
                                "
                                @keyup="
                                    (e: any) =>
                                        handleInput(e, procedureForm, {
                                            config: item
                                        })
                                "
                                @blur="popoverVisible = false"
                            />
                        </q-form-item>
                    </el-col>
                </el-row>
                <br />
                <base-table
                    ref="tableRef"
                    :table-config="tableConfig"
                    :table-attr="{ showOverflowTooltip: false, highlightCurrentRow: false }"
                    :show-setting="false"
                    :show-page="false"
                    :max-height="getMaxHeight"
                    :modal-mode="true"
                    open-sticky
                    class="h-border m-procedure--add"
                    @add="handleAdd"
                >
                    <!--  设备编码  -->
                    <template #workingProcedureEquipments="{ row, index }">
                        <q-form-item
                            id="1"
                            class="m-equipment__code"
                            :style="{
                                'padding-bottom': getDynamicPBottom(row.workingProcedureAuxiliary)
                            }"
                        >
                            <q-virtual-select
                                v-model="row.equipmentNumber"
                                placeholder="请选择"
                                icon-class="xiala"
                                size="14px"
                                @click="openEquipment(row, index)"
                                @clear="clearEquipmentSelect(row)"
                            />

                            <q-icon
                                icon-class="a-zuhe560"
                                class="m-l-8 hover-icon"
                                size="21"
                                @click="addEquipment(row.markId)"
                            />
                            <q-icon
                                icon-class="a-zuhe557"
                                class="m-l-8 hover-icon"
                                size="20"
                                @click="delEquipment(row.markId, index)"
                            />
                        </q-form-item>
                    </template>

                    <!-- 设备名称 -->
                    <template #workingProcedureEquipmentsName="{ row }">
                        <p
                            class="u-text"
                            :style="{
                                'padding-bottom': getDynamicPBottom(row.workingProcedureAuxiliary)
                            }"
                        >
                            {{ transformValue(row.deviceName) }}
                        </p>
                    </template>

                    <!--  辅助资源编码  -->
                    <template #workingProcedureAuxiliary="{ row }">
                        <q-form-item
                            v-for="item in row.workingProcedureAuxiliary"
                            id="2"
                            :key="item.auxiliaryId!"
                            class="m-equipment__code"
                        >
                            <q-virtual-select
                                v-model="item.auxiliaryDataCoding"
                                placeholder="请选择"
                                icon-class="xiala"
                                size="14px"
                                @click="openAuxiliary(item)"
                                @clear="clearAuxiliarySelect(item)"
                            />
                            <q-icon
                                icon-class="a-zuhe560"
                                class="m-l-8 hover-icon"
                                size="21"
                                @click="addAuxiliary(item)"
                            />
                            <q-icon
                                icon-class="a-zuhe557"
                                class="m-l-8 hover-icon"
                                size="20"
                                @click="delAuxiliary(item)"
                            />
                        </q-form-item>
                    </template>

                    <!-- 辅助资源名称 -->
                    <template #workingProcedureAuxiliaryName="{ row }">
                        <p
                            v-for="(item, index) in row.workingProcedureAuxiliary"
                            :key="index"
                            class="u-text"
                        >
                            {{ transformValue(item.auxiliaryResourceName) }}
                        </p>
                    </template>
                </base-table>
            </div>

            <!-- 加工设备 -->
            <equipment ref="equipmentRef" @submit="equipmentSubmit" @close="visible = false" />

            <!-- 辅助资源 -->
            <auxiliary ref="auxiliaryRef" @submit="auxiliarySubmit" @close="visible = false" />

            <!-- 校验提示框 -->
            <q-valid-popover
                :popover-visible="popoverVisible"
                :popover-err-msg="popoverErrMsg"
                position="left"
            />
        </q-modal>
    </div>
</template>

<style scoped lang="scss">
@include b(role-main-form) {
    @include e(item) {
        width: 100%;
        max-width: 1000px;
    }
}

@include b(role-main__header) {
    color: var(--el-color-danger);
}

@include b(main) {
    width: 90%;
    margin: 0 auto;
}

@include b(title) {
    font-weight: 700;
}

@include b(m-equipment) {
    @include e(code) {
        @include flex();
    }
}

:deep() {
    @include b(m-procedure) {
        @include m(add) {
            .el-table .el-table__cell {
                vertical-align: top;
            }

            td.custom-cell {
                padding: 0;

                .cell {
                    padding: 0;
                }

                .q-form-item__content,
                .u-text {
                    &:last-child {
                        border-bottom: none;
                    }

                    padding: 8px 12px;
                    line-height: 32px;
                    border-bottom: var(--el-table-border);
                }
            }
        }
    }
}
</style>
